import 'dart:math';
import 'package:flutter/material.dart';

import '../../../utils/ex/kq_ex.dart';
import '../ex/extension.dart';
import '../base/base_chart.dart';
import 'base/axis.dart';
import 'base/base_radar_chart.dart';
import 'radar_entity.dart';

/// 雷达图
class KqRadarChartDelegate extends BaseRadarChartDelegate<List<RadarData>> {
  KqRadarChartDelegate(
      {required super.radius,
      RadarXAxisRender? xAxisRender,
      RadarYAxisRender? yAxisRender,
      RadarDataRender? dataRender,
      RadarXAxis? xAxis,
      RadarYAxis? yAxis,
      super.animDuration,
      super.data,
      super.drawStartAngle,
      RadarChartGestureHandler? gestureHandler,
      super.emptyWidgetBuilder,
      super.isDataEmpty})
      : super(
          xAxisRender: xAxisRender ?? RadarXAxisRender(),
          yAxisRender: yAxisRender ?? RadarYAxisRender(),
          dataRender: dataRender ?? const RadarDataRender(),
          xAxis: xAxis ?? RadarXAxis(),
          yAxis: yAxis ?? RadarYAxis(),
          gestureHandler: gestureHandler,
        );

  KqRadarChartDelegate.withDefault(
      {required double radius,
      RadarXAxisRender? xAxisRender,
      RadarYAxisRender? yAxisRender,
      RadarDataRender? dataRender,
      RadarXAxis? xAxis,
      RadarYAxis? yAxis,
      Duration? animDuration,
      List<RadarData>? data,
      double drawStartAngle = 0,
      RadarChartGestureHandler? gestureHandler,
      Widget Function()? emptyWidgetBuilder,
      bool Function(List<RadarData>? data)? isDataEmpty})
      : this(
            radius: radius,
            xAxisRender: xAxisRender,
            yAxisRender: yAxisRender,
            dataRender: dataRender,
            xAxis: xAxis,
            yAxis: yAxis,
            animDuration: animDuration,
            data: data,
            drawStartAngle: drawStartAngle,
            gestureHandler: gestureHandler ?? RadarChartGestureHandler(),
            isDataEmpty: isDataEmpty,
            emptyWidgetBuilder: emptyWidgetBuilder ?? getDefEmptyView);

  @override
  RadarXAxis get xAxis => super.xAxis as RadarXAxis;

  @override
  RadarYAxis get yAxis => super.yAxis as RadarYAxis;

  @override
  bool get isEmptyData {
    var isDataEmptyFunc = isDataEmpty;
    if (isDataEmptyFunc != null) {
      return isDataEmptyFunc.call(data);
    }

    return data.isNullOrEmpty;
  }

  @override
  void didUpdateWidget(covariant BaseChart oldWidget) {
    super.didUpdateWidget(oldWidget);
    _updateGestureHandler(oldWidget);
  }

  void _updateGestureHandler(BaseChart oldWidget) {
    var gestureHandler = this.gestureHandler;
    if (gestureHandler == null || gestureHandler is! RadarChartGestureHandler) {
      return;
    }

    var oldGestureHandler = oldWidget.delegate.gestureHandler;
    if (oldGestureHandler == null ||
        oldGestureHandler is! RadarChartGestureHandler) {
      return;
    }

    gestureHandler._rotation = oldGestureHandler._rotation;
    gestureHandler._firstMoveAngle = oldGestureHandler._firstMoveAngle;
    gestureHandler._touchData = oldGestureHandler._touchData;
    gestureHandler._lastPoint = oldGestureHandler._lastPoint;
    gestureHandler._isCouldMove = oldGestureHandler._isCouldMove;
  }
}

/// 雷达图X轴绘制器
class RadarXAxisRender with BaseRadarAxisRender<KqRadarChartDelegate> {
  @override
  void onDraw(KqRadarChartDelegate chart, Canvas canvas) {
    RadarChartGestureHandler? gestureHandler = chart.gestureHandler == null
        ? null
        : chart.gestureHandler as RadarChartGestureHandler;

    double angle = chart.drawStartAngle + (gestureHandler?.rotation ?? 0);
    double stepAngle = 360.0 / chart.xAxis.labelCount;
    Offset center = chart.size.center(Offset.zero);

    Path path = Path();

    var textPaint = TextPainter(
      maxLines: 2,
      textAlign: TextAlign.center,
      textDirection: TextDirection.ltr,
    );

    Paint paint = Paint();
    paint.color = chart.xAxis.lineColor;
    paint.strokeWidth = chart.xAxis.lineWidth;
    paint.style = PaintingStyle.stroke;

    for (int i = 0; i < chart.xAxis.labelCount; i++) {
      var radian = angle.toRadian;
      double startY;
      double startX;

      if (chart.xAxis.lineStartOffset > 0) {
        startY = center.dy + sin(radian) * chart.xAxis.lineStartOffset;
        startX = center.dx + cos(radian) * chart.xAxis.lineStartOffset;
      } else {
        startY = center.dy;
        startX = center.dx;
      }

      var endX = center.dx + cos(radian) * chart.radius;
      var endY = center.dy + sin(radian) * chart.radius;

      path.reset();
      path.moveTo(startX, startY);
      path.lineTo(endX, endY);
      if (chart.xAxis.lineDash != null) {
        canvas.drawPath(path.dashPath(chart.xAxis.lineDash!), paint);
      } else {
        canvas.drawPath(path, paint);
      }

      drawLabel(
        canvas,
        i,
        angle,
        stepAngle,
        endX,
        endY,
        chart.xAxis,
        textPaint,
      );
      angle += stepAngle;
    }
    textPaint.dispose();
  }

  @protected
  void drawLabel(Canvas canvas, int pos, double angle, double stepAngle,
      double endX, double endY, RadarXAxis xAxis, TextPainter textPaint) {
    var text = xAxis.valueFormatter?.call(pos);
    if (text == null || text.isEmpty) {
      return;
    }

    var textDec = xAxis.valueDesFormatter?.call(pos);
    if (textDec.isNotNullOrEmpty) {
      textPaint
        ..text = TextSpan(
            text: '$textDec\n',
            children: [
              TextSpan(
                  text: text,
                  style: TextStyle(
                      color: xAxis.labelColor,
                      fontSize: xAxis.labelTextSize,
                      fontWeight: FontWeight.normal))
            ],
            style: TextStyle(
                color: xAxis.labelDecColor,
                fontSize: xAxis.labelTextDecSize,
                fontWeight: xAxis.labelTextDecFontWeight))
        ..layout();
    } else {
      textPaint
        ..text = TextSpan(
            text: text,
            style: TextStyle(
                color: xAxis.labelColor, fontSize: xAxis.labelTextSize))
        ..layout();
    }

    drawLabelAroundRadar(
        canvas, textPaint, angle, endX, endY, xAxis.labelOffsetAxis);
  }

  /// 围绕雷达绘制标签，根据雷达图偏转角度[angle]动态调整标签位置。
  ///
  /// [textPaint]则为需要绘制文本的画笔，此画笔需要设置好要绘制的文本及执行过layout操作。
  /// [drawX]、[drawY]为标签绘制的坐标点，[labelOffset]为偏移[drawX]、[drawY]的距离，>0远离，<0则靠近。
  static drawLabelAroundRadar(Canvas canvas, TextPainter textPaint,
      double angle, double drawX, double drawY, double labelOffset) {
    var textHeight = textPaint.height;
    var textWidth = textPaint.width;

    var mapAngle = angle.to360Range;
    var radian = mapAngle.toRadian;
    var x = drawX + cos(radian) * labelOffset;
    var y = drawY + sin(radian) * labelOffset;

    var cosV = cos(mapAngle.toRadian);
    var sinV = sin(mapAngle.toRadian);

    double labelOffsetAxis = (labelOffset + textHeight / 2);

    double labelOffsetX;
    double labelOffsetY;
    if (mapAngle >= 0 && mapAngle <= 45) {
      labelOffsetY = tan(mapAngle.toRadian) * labelOffsetAxis * sinV;
      labelOffsetX = tan(mapAngle.toRadian) * labelOffsetAxis * cosV;
    } else if (mapAngle <= 90) {
      labelOffsetY = tan((90 - mapAngle).toRadian) * labelOffsetAxis * sinV;
      labelOffsetX = tan((90 - mapAngle).toRadian) * labelOffsetAxis * cosV;
    } else if (mapAngle <= 135) {
      labelOffsetY = tan((mapAngle - 90).toRadian) * labelOffsetAxis * sinV;
      labelOffsetX = tan((mapAngle - 90).toRadian) * labelOffsetAxis * cosV;
    } else if (mapAngle <= 180) {
      labelOffsetY = tan((180 - mapAngle).toRadian) * labelOffsetAxis * sinV;
      labelOffsetX = tan((180 - mapAngle).toRadian) * labelOffsetAxis * cosV;
    } else if (mapAngle <= 225) {
      labelOffsetY = tan((mapAngle - 180).toRadian) * labelOffsetAxis * sinV;
      labelOffsetX = tan((mapAngle - 180).toRadian) * labelOffsetAxis * cosV;
    } else if (mapAngle <= 270) {
      labelOffsetY = tan((270 - mapAngle).toRadian) * labelOffsetAxis * sinV;
      labelOffsetX = tan((270 - mapAngle).toRadian) * labelOffsetAxis * cosV;
    } else if (mapAngle <= 315) {
      labelOffsetY = tan((mapAngle - 270).toRadian) * labelOffsetAxis * sinV;
      labelOffsetX = tan((mapAngle - 270).toRadian) * labelOffsetAxis * cosV;
    } else {
      labelOffsetY = tan((360 - mapAngle).toRadian) * labelOffsetAxis * sinV;
      labelOffsetX = tan((360 - mapAngle).toRadian) * labelOffsetAxis * cosV;
    }

    textPaint.paint(
        canvas,
        Offset(x - textWidth / 2 + cosV * textWidth / 2 + labelOffsetX,
            y - textHeight / 2 + sinV * (textHeight / 2) + labelOffsetY));
  }
}

/// 雷达图Y轴绘制器
class RadarYAxisRender with BaseRadarAxisRender<KqRadarChartDelegate> {
  @override
  void onDraw(KqRadarChartDelegate chart, Canvas canvas) {
    var xAxis = chart.xAxis;
    var yAxis = chart.yAxis;

    var radius2 = chart.radius - xAxis.lineEndPadding;
    if (radius2 <= 0) {
      return;
    }

    double radiusStep =
        yAxis.labelCount == 1 ? 0 : radius2 / (yAxis.labelCount - 1);
    Offset center = chart.size.center(Offset.zero);
    RadarChartGestureHandler? gestureHandler = chart.gestureHandler == null
        ? null
        : chart.gestureHandler as RadarChartGestureHandler;

    double startAngle = chart.drawStartAngle + (gestureHandler?.rotation ?? 0);

    if (yAxis.labelCount > 1) {
      double startRadius = radiusStep;

      Paint paint = Paint();
      Path path = Path();

      paint.color = yAxis.lineColor;
      paint.strokeWidth = yAxis.lineWidth;
      paint.style = PaintingStyle.stroke;
      for (int i = 1; i < yAxis.labelCount; i++) {
        if (yAxis.lineDrawConfig != null &&
            yAxis.lineDrawConfig?.call(i) != true) {
          startRadius += radiusStep;
          continue;
        }

        path.reset();
        if (yAxis.lineStyle == LineStyle.liner) {
          var angle = startAngle;
          var stepAngle = 360 / xAxis.labelCount;
          for (int j = 0; j < xAxis.labelCount; j++) {
            var radian = angle.toRadian;
            var x = center.dx + cos(radian) * startRadius;
            var y = center.dy + sin(radian) * startRadius;
            if (j == 0) {
              path.moveTo(x, y);
            } else {
              path.lineTo(x, y);
            }
            angle += stepAngle;
          }
          path.close();
        } else {
          path.addOval(Rect.fromCircle(center: center, radius: startRadius));
        }

        var lineDash = yAxis.lineDashConfig?.call(i) ?? yAxis.lineDash;
        if (lineDash != null) {
          canvas.drawPath(path.dashPath(lineDash), paint);
        } else {
          canvas.drawPath(path, paint);
        }

        startRadius += radiusStep;
      }
    }

    if (yAxis.drawLabel) {
      drawLabel(canvas, yAxis, xAxis, startAngle, center, radiusStep);
    }
  }

  @protected
  void drawLabel(Canvas canvas, RadarYAxis yAxis, RadarXAxis xAxis,
      double startAngle, Offset center, double radiusStep) {
    var angle = (yAxis.labelDrawStartAngle + startAngle).to360Range;
    var radian = angle.toRadian;

    // 需要求出半径的一边对应的角
    double angleA = 0;
    // 雷达图构成的三角形过圆心的那一边对应的角
    double angleC = 0;
    if (yAxis.lineStyle == LineStyle.liner) {
      // 利用正弦定理求出圆心与雷达图三角形边上交点半径距离
      var inAngle = startAngle.to360Range;
      double stepAngle = 360 / xAxis.labelCount;
      for (int j = 0; j < xAxis.labelCount; j++) {
        if (inAngle >= angle) {
          break;
        }
        inAngle += stepAngle;
      }

      if (inAngle == angle) {
        angleA = 90;
        angleC = 90;
      } else if (inAngle > angle) {
        var angleB = inAngle - angle;
        angleA = (180 - stepAngle) / 2;
        angleC = 180 - angleA - angleB;
      } else {
        var angleB = angle - inAngle;
        angleA = (180 - stepAngle) / 2;
        angleC = 180 - angleA - angleB;
      }
    }

    var textPaint = TextPainter(
        textDirection: TextDirection.ltr,
        maxLines: 1,
        textAlign: TextAlign.left);
    for (int i = 0; i < yAxis.labelCount; i++) {
      if (yAxis.lineDrawConfig != null &&
          yAxis.lineDrawConfig?.call(i) != true) {
        continue;
      }

      var label = yAxis.valueFormatter?.call(i);
      if (label == null || label.isEmpty) {
        continue;
      }

      textPaint
        ..text = TextSpan(
            text: label,
            style: TextStyle(
                color: yAxis.labelColor, fontSize: yAxis.labelTextSize))
        ..layout();

      var radius = (radiusStep * i + yAxis.labelOffsetAxis);
      double x;
      double y;
      if (yAxis.lineStyle == LineStyle.circle) {
        x = center.dx + cos(radian) * radius;
        y = center.dy + sin(radian) * radius;
      } else {
        // 雷达图绘制的是多边形，则需要求与三角形边的交点半径距离
        radius = radius / sin(angleC.toRadian) * sin(angleA.toRadian);
        x = center.dx + cos(radian) * radius;
        y = center.dy + sin(radian) * radius;
      }

      var textWidth = textPaint.width;
      var textHeight = textPaint.height;
      textPaint.paint(
          canvas,
          Offset(x - textWidth / 2 + cos(angle.toRadian) * textWidth / 2,
              y - textHeight / 2 + sin(angle.toRadian) * (textHeight / 2)));
    }
    textPaint.dispose();
  }
}

/// 雷达图数据绘制器
class RadarDataRender with BaseRadarDataRender<KqRadarChartDelegate> {
  const RadarDataRender({this.highLightRender});

  final RadarChartHighLightRender? highLightRender;

  @override
  void onDraw(
      KqRadarChartDelegate chart, Canvas canvas, double animProgress) async {
    var radius = chart.radius - chart.xAxis.lineEndPadding;
    if (radius <= 0) {
      return;
    }

    var dataList = chart.data;
    if (dataList == null || dataList.isEmpty) {
      return;
    }

    var xAxis = chart.xAxis;
    var yAxis = chart.yAxis;
    double stepAngle = 360 / xAxis.labelCount;
    Path path = Path();
    Offset center = chart.size.center(Offset.zero);
    double range = yAxis.max - yAxis.min;
    RadarChartGestureHandler? gestureHandler = chart.gestureHandler == null
        ? null
        : chart.gestureHandler as RadarChartGestureHandler;

    double startAngle = chart.drawStartAngle + (gestureHandler?.rotation ?? 0);

    Paint paint = Paint();
    paint.style = PaintingStyle.stroke;

    for (var value in dataList) {
      var values = value.values;
      if (values == null || values.isEmpty) {
        continue;
      }

      path.reset();
      for (int index = 0; index < values.length; index++) {
        var data = values[index];
        if (data.xIndex < 0 || data.xIndex >= xAxis.labelCount) {
          continue;
        }

        double percent = range <= 0 ? 0 : (data.value - yAxis.min) / range;
        double radian = (startAngle + stepAngle * data.xIndex).toRadian;
        double x = center.dx + cos(radian) * radius * percent * animProgress;
        double y = center.dy + sin(radian) * radius * percent * animProgress;
        data.$drawRect = Rect.fromLTRB(x, y, x, y);
        if (index == 0) {
          path.moveTo(x, y);
        } else {
          path.lineTo(x, y);
        }
      }
      path.close();
      if (value.fillBg) {
        drawFillBg(chart, canvas, path, value, center, radius);
      }
      Paint paint = Paint()
        ..style = PaintingStyle.stroke
        ..color = value.lineColor
        ..strokeWidth = value.lineWidth;
      canvas.drawPath(path, paint);
      drawValueTextAndIndicator(chart, canvas, value, animProgress);
    }

    if (animProgress >= 1 && highLightRender != null) {
      var touchData = gestureHandler?.touchData;
      if (touchData != null && touchData.isNotEmpty) {
        for (var value in touchData) {
          highLightRender?.onDraw(canvas, value);
        }
      }
    }
  }

  /// 绘制折线背景填充色
  @protected
  void drawFillBg(KqRadarChartDelegate chart, Canvas canvas, Path path,
      RadarData radarData, Offset center, double radius) {
    if (radarData.fillBgDrawable != null) {
      canvas.save();
      canvas.clipPath(path);
      canvas.drawImage(
          radarData.fillBgDrawable!,
          center.translate(-radarData.fillBgDrawable!.width / 2,
              -radarData.fillBgDrawable!.height / 2),
          Paint());
      canvas.restore();
    } else if (radarData.fillBgColor != null) {
      canvas.save();
      canvas.clipPath(path);
      canvas.drawColor(radarData.fillBgColor!, BlendMode.srcOver);
      canvas.restore();
    }
  }

  /// 绘制文本值和数值指示器
  @protected
  void drawValueTextAndIndicator(KqRadarChartDelegate chart, Canvas canvas,
      RadarData radarData, double animProgress) {
    var values = radarData.values;
    if (values == null || values.isEmpty) {
      return;
    }

    var textPainter = TextPainter(
        maxLines: 1,
        textAlign: TextAlign.center,
        textDirection: TextDirection.ltr);
    double stepAngle = 360.0 / chart.xAxis.labelCount;
    var gestureHandler = chart.gestureHandler == null
        ? null
        : chart.gestureHandler as RadarChartGestureHandler;
    double angle = chart.drawStartAngle + (gestureHandler?.rotation ?? 0);
    for (var entity in values) {
      var indicatorOffset = entity.labelOffset;
      if (entity.drawIndicator &&
          (entity.indicatorDrawable != null || entity.indicatorColor != null) &&
          entity.indicatorSize > 0) {
        var half = entity.indicatorSize / 2;
        if (entity.indicatorDrawable != null) {
          canvas.drawImage(
              entity.indicatorDrawable!,
              entity.drawRect.center.translate(
                  entity.indicatorDrawable!.width / 2,
                  entity.indicatorDrawable!.height / 2),
              Paint());
        } else {
          canvas.drawCircle(entity.drawRect.center, half,
              Paint()..color = entity.indicatorColor!);
        }
        indicatorOffset += half;
      }

      var label = entity.label;
      if (entity.drawLabel &&
          label.isNotNullOrEmpty &&
          entity.labelTextSize > 0 &&
          animProgress >= 1) {
        textPainter
          ..text = TextSpan(
              text: label,
              style: TextStyle(
                  color: entity.labelColor, fontSize: entity.labelTextSize))
          ..layout();

        RadarXAxisRender.drawLabelAroundRadar(canvas, textPainter, angle,
            entity.drawRect.left, entity.drawRect.top, indicatorOffset);
        angle += stepAngle;
      }
    }
    textPainter.dispose();
  }
}

/// 雷达图手势处理器
class RadarChartGestureHandler
    with BaseChartGestureHandlerMixin<KqRadarChartDelegate> {
  /// 构建手势处理器
  ///
  /// [touchData]为当前选中数据，主动赋值相当于模拟用户点击
  RadarChartGestureHandler(
      {this.tapEnable = true,
      this.dragEnable = true,
      this.onTap,
      List<RadarEntity>? touchData}) {
    _touchData = touchData;
  }

  @override
  final bool tapEnable;

  /// 是否支持旋转
  @override
  final bool dragEnable;

  /// 点击监听，回调参数为空说明点击了非特定数据区域，不为空则为某个数据的绘制区域
  final RadarChartTapCallback? onTap;

  double _rotation = 0;
  double? _firstMoveAngle;
  AnimationController? _animationController;
  Offset? _lastPoint;
  bool _isCouldMove = false;
  List<RadarEntity>? _touchData;

  KqRadarChartDelegate? _delegate;

  @override
  void attachChart(KqRadarChartDelegate delegate) {
    _animationController?.dispose();
    _delegate = delegate;
  }

  @override
  void dispose() {
    _animationController?.dispose();
    _delegate = null;
  }

  @override
  void onTapDown(DragDownDetails details) {
    if ((!tapEnable && !dragEnable) || _delegate == null) {
      return;
    }

    if (_animationController != null && _animationController!.isAnimating) {
      _animationController?.stop(canceled: true);
    }

    _isCouldMove = isCloudMove(details);
    _firstMoveAngle = null;
    _lastPoint = details.localPosition;
  }

  @override
  void onTapUp(DragDownDetails details) {
    if (!tapEnable || _delegate == null || _lastPoint == null) {
      return;
    }

    findTouchInRange(_lastPoint!, _firstMoveAngle != null);
  }

  @override
  void onDragEnd(DragEndDetails details) {
    if (_delegate == null || !dragEnable) {
      return;
    }

    flingRotation(details);
  }

  @override
  void onDragStart(DragStartDetails details) {}

  @override
  void onDragUpdate(DragUpdateDetails details) {
    if (_delegate == null || !_isCouldMove) {
      return;
    }

    _lastPoint = details.localPosition;
    var angle =
        getAngleForPoint(details.localPosition.dx, details.localPosition.dy);
    if (_firstMoveAngle == null) {
      _firstMoveAngle = angle;
    } else {
      _rotation += angle - _firstMoveAngle!;
      _rotation = _rotation.to360Range;
      _firstMoveAngle = angle;
      _delegate?.update();
    }
  }

  @protected
  bool isCloudMove(DragDownDetails details) {
    if (!dragEnable || _delegate == null) {
      return false;
    }

    var center = _delegate!.size.center(Offset.zero);
    return sqrt(pow((center.dx - details.localPosition.dx), 2) +
            pow(center.dy - details.localPosition.dy, 2)) <=
        _delegate!.radius;
  }

  @protected
  void findTouchInRange(Offset point, bool isMove) {
    var data = findClickData(point);
    if (data == null) {
      if (!isMove && _touchData != null) {
        _touchData = null;
        _delegate?.update();
        onTap?.call(_touchData);
      }
      return;
    }

    _touchData = data;
    _delegate?.update();
    onTap?.call(_touchData);
  }

  @protected
  List<RadarEntity>? findClickData(Offset point) {
    if (_delegate?.data == null || _delegate!.data!.isEmpty) {
      return null;
    }

    List<RadarEntity> inRangePoint = [];
    for (var data in _delegate!.data!) {
      if (data.values.isNullOrEmpty) {
        continue;
      }

      for (var value in data.values!) {
        if (isTouchInRectF(point.dx, point.dy, value.drawRect)) {
          inRangePoint.add(value);
          break;
        }
      }
    }

    return inRangePoint.isEmpty ? null : inRangePoint;
  }

  /// 点击是否在指定范围内容
  @protected
  bool isTouchInRectF(double x, double y, Rect rect) {
    double validRange = 10;
    if (x >= rect.left - validRange && x <= rect.left + validRange) {
      return y >= rect.top - validRange && y <= rect.top + validRange;
    }

    return false;
  }

  /// 获取触摸点相对于圆心的旋转角度
  @protected
  double getAngleForPoint(double x, double y) {
    var offset = _delegate?.size.center(Offset.zero);
    if (offset == null) {
      return 0;
    }

    double tx = x - offset.dx;
    double ty = y - offset.dy;
    double length = sqrt(tx * tx + ty * ty);
    double r = acos(tx / length);
    var angle = r.toDegrees;
    if (y < offset.dy) angle = 360 - angle;
    return angle % 360;
  }

  /// 执行手势旋转动画
  @protected
  void flingRotation(DragEndDetails details) {
    var velocity = details.velocity.pixelsPerSecond;
    if (velocity.dx == 0 && velocity.dy == 0) {
      return;
    }

    KqRadarChartDelegate? chart = _delegate;
    if (chart == null) {
      return;
    }

    var state = chart.chartState;
    if (state == null) {
      return;
    }

    double angleStep;
    Offset center = chart.size.center(Offset.zero);
    double maxAngle = 8;
    int duration;
    if (velocity.dx.abs() > velocity.dy.abs()) {
      duration = velocity.dx.abs() ~/ 2;
      if (velocity.dx > 0) {
        angleStep = (_lastPoint?.dy ?? 0) > center.dy ? -maxAngle : maxAngle;
      } else {
        angleStep = (_lastPoint?.dy ?? 0) > center.dy ? maxAngle : -maxAngle;
      }
    } else {
      duration = velocity.dy.abs() ~/ 2;
      if (velocity.dy > 0) {
        angleStep = (_lastPoint?.dx ?? 0) > center.dx ? maxAngle : -maxAngle;
      } else {
        angleStep = (_lastPoint?.dx ?? 0) > center.dx ? -maxAngle : maxAngle;
      }
    }

    if (_animationController?.isAnimating == true) {
      _animationController?.stop(canceled: true);
    }

    TickerProviderStateMixin;
    _animationController = AnimationController(
        vsync: state.vsync, duration: Duration(milliseconds: duration));
    var curvedAnimation = CurvedAnimation(
        parent: _animationController!, curve: Curves.decelerate);
    curvedAnimation.addListener(() {
      _rotation += angleStep * (1 - _animationController!.value);
      _rotation = _rotation.to360Range;
      state.update();
    });
    _animationController?.forward();
  }

  List<RadarEntity>? get touchData => _touchData;

  double get rotation => _rotation;
}

/// 雷达图点击回调
typedef RadarChartTapCallback = Function(List<RadarEntity>? data);

/// 雷达图高亮数据绘制器
class RadarChartHighLightRender {
  const RadarChartHighLightRender(
      {this.maskColor = const Color(0x33000000), this.radiusPercent = 1.5});

  final Color maskColor;
  final double radiusPercent;

  void onDraw(Canvas canvas, RadarEntity data) {
    var paint = Paint();
    paint.color = maskColor;
    canvas.drawCircle(
        data.drawRect.center, data.indicatorSize * radiusPercent, paint);
  }
}
